
import UIKit

func c_make<Base: UIView>(_ type: Base.Type) -> Base {
    return type.init()
}

func c_make_ex<Base: UIView>(_ type: Base.Type) -> FJMakeViewWrapper<Base> {
    return type.init().fj
}

struct FJMakeViewWrapper<Base> {
    let base: Base
    init(_ base: Base) {
        self.base = base
    }
}

protocol FJMakeViewProtocol { }
extension UIView: FJMakeViewProtocol { }

extension FJMakeViewProtocol {
    ///
    var fj: FJMakeViewWrapper<Self> {
        get { return FJMakeViewWrapper(self) }
        set { }
    }
    
}

//TODO: - Frame
extension FJMakeViewWrapper where Base: UIView {
    
    @discardableResult
    func frame(_ frame: CGRect) -> Self {
        base.frame = frame
        return self
    }
    
    @discardableResult
    func size(_ size: CGSize) -> Self {
        base.frame = CGRect(origin: base.frame.origin, size: size)
        return self
    }
    
    @discardableResult
    func size(_ size: CGFloat) -> Self {
        base.frame = CGRect(origin: base.frame.origin, size: CGSize(width: size, height: size))
        return self
    }
    
    @discardableResult
    func width(_ width: CGFloat) -> Self {
        base.frame = CGRect(origin: base.frame.origin, size: CGSize(width: width, height: base.frame.height))
        return self
    }
    
    @discardableResult
    func height(_ height: CGFloat) -> Self {
        base.frame = CGRect(origin: base.frame.origin, size: CGSize(width: base.frame.width, height: height))
        return self
    }
    
    @discardableResult
    func origin(_ origin: CGPoint) -> Self {
        base.frame = CGRect(origin: origin, size: base.frame.size)
        return self
    }
    
    @discardableResult
    func x(_ x: CGFloat) -> Self {
        base.frame = CGRect(origin: CGPoint(x: x, y: base.frame.minY), size: base.frame.size)
        return self
    }
    
    @discardableResult
    func y(_ y: CGFloat) -> Self {
        base.frame = CGRect(origin: CGPoint(x: base.frame.minX, y: y), size: base.frame.size)
        return self
    }
    
}

//TODO: - 通用属性
extension FJMakeViewWrapper where Base: UIView {
    
    @discardableResult
    func tag(_ tag: Int) -> Self {
        base.tag = tag
        return self
    }
    
    @discardableResult
    func bgColor(_ color: UIColor) -> Self {
        base.backgroundColor = color
        return self
    }
    
    @discardableResult
    func bgColor(_ color: String) -> Self {
        bgColor(color.toColor)
    }
    
    /// 边框
    @discardableResult
    func border(_ color: UIColor, width: CGFloat = 2.0) -> Self {
        base.layer.borderColor = color.cgColor
        base.layer.borderWidth = width
        return self
    }
    
    @discardableResult
    func border(_ color: String, width: CGFloat = 2.0) -> Self {
        border(color.toColor, width: width)
    }
    
    /// 圆角
    @discardableResult
    func corner(_ radius: CGFloat, corners: CACornerMask = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]) -> Self {
        base.layer.cornerRadius = radius
        base.layer.maskedCorners = corners
        base.layer.masksToBounds = true
        return self
    }
    
    @discardableResult
    func shadow(_ color: UIColor, radius: CGFloat, opacity: Float = 0, offset: CGSize = .zero) -> Self {
        base.layer.shadowColor = color.cgColor
        base.layer.shadowRadius = radius
        base.layer.shadowOpacity = opacity
        base.layer.shadowOffset = offset
        // 添加阴影大部分情况下，都需要将 masksToBounds 设置为 false
        base.layer.masksToBounds = false
        return self
    }
    
    @discardableResult
    func shadow(_ color: String, radius: CGFloat, opacity: Float = 0, offset: CGSize = .zero) -> Self {
        shadow(color.toColor, radius: radius, opacity: opacity, offset: offset)
    }
    
    @discardableResult
    func tapGesture(_ target: Any?, selector: Selector) -> Self {
        let tapGesture = UITapGestureRecognizer(target: target, action: selector)
        base.addGestureRecognizer(tapGesture)
        base.isUserInteractionEnabled = true
        return self
    }
    
    //TODO: - 添加下划线
    @discardableResult
    func addUnderline() -> Self {
        guard self.base.isKind(of: UIButton.classForCoder()) || self.base.isKind(of: UILabel.classForCoder()) else {
            return self
        }
        var attribute: NSMutableAttributedString?
        if let label = self.base as? UILabel {
            if let text = label.attributedText {
                attribute = NSMutableAttributedString(attributedString: text)
            } else {
                attribute = NSMutableAttributedString(string: label.text ?? "")
            }
        } else if let button = self.base as? UIButton {
            if let text = button.currentAttributedTitle {
                attribute = NSMutableAttributedString(attributedString: text)
            } else {
                attribute = NSMutableAttributedString(string: button.currentTitle ?? "")
            }
        }
        let textCount = attribute?.length ?? 0
        attribute?.addAttribute(.underlineStyle, value: 1, range: NSRange(location: 0, length: textCount))
        
        if let label = self.base as? UILabel {
            label.attributedText = attribute
        } else if let button = self.base as? UIButton {
            button.setAttributedTitle(attribute, for: .normal)
        }
        return self
    }
    
    // 将当前视图转为UIImage
    func toImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: base.bounds)
        return renderer.image { rendererContext in
            base.layer.render(in: rendererContext.cgContext)
        }
    }
    
    func end() -> Base {
        return base
    }
}

//TODO: - 渐变色
extension FJMakeViewWrapper where Base: UIView {
    
    enum SmallP_GradientType {
        case topToBottom(_ colors: [UIColor])
        case leftToRight(_ colors: [UIColor])
        case bottomToTop(_ colors: [UIColor])
        case rightToLeft(_ colors: [UIColor])

        case leftTopToRightBottom(_ colors: [UIColor])
        case rightTopToLeftBottom(_ colors: [UIColor])
        case leftBottomToRightTop(_ colors: [UIColor])
        case rightBottomToLeftTop(_ colors: [UIColor])
        
        var raw: String {
            switch self {
            case .topToBottom:
                return "0001"
            case .leftToRight:
                return "0010"
            case .bottomToTop:
                return "0100"
            case .rightToLeft:
                return "1000"
            case .leftTopToRightBottom:
                return "0011"
            case .rightTopToLeftBottom:
                return "1001"
            case .leftBottomToRightTop:
                return "0110"
            case .rightBottomToLeftTop:
                return "1100"
            }
        }
        
        var colors: [UIColor] {
            switch self {
            case .topToBottom(let colors):
                return colors
            case .leftToRight(let colors):
                return colors
            case .bottomToTop(let colors):
                return colors
            case .rightToLeft(let colors):
                return colors
            case .leftTopToRightBottom(let colors):
                return colors
            case .rightTopToLeftBottom(let colors):
                return colors
            case .leftBottomToRightTop(let colors):
                return colors
            case .rightBottomToLeftTop(let colors):
                return colors
            }
        }
    }
    
    //TODO: - 绘制渐变色（单色值绘制）
    @discardableResult
    func gradientColors(_ gradientType: SmallP_GradientType, fromAlpha: CGFloat = 0, toAlpha: CGFloat = 1.0, size: CGSize = .zero) -> Self {
        guard let color = gradientType.colors.first else { return self }
        base.layer.sublayers?.forEach({ layer in
            if layer.name == "GRADIENTCOLORS" {
                layer.removeFromSuperlayer()
            }
        })
        let startAlpha = max(0, fromAlpha)
        let endAlpha = min(1, toAlpha)
        let gradientLayer = CAGradientLayer()
        gradientLayer.name = "GRADIENTCOLORS"
        gradientLayer.colors = [color.withAlphaComponent(startAlpha).cgColor, color.withAlphaComponent(endAlpha).cgColor]
        base.layoutIfNeeded()
        gradientLayer.frame = size == .zero ? base.bounds : CGRect(origin: .zero, size: size)
        startAndEndPoint(gradientLayer, direction: gradientType)
        base.layer.insertSublayer(gradientLayer, at: 0)
        return self
    }
    
    //TODO: - 绘制渐变色（多色值绘制）
    @discardableResult
    func gradientColors(_ gradientType: SmallP_GradientType, size: CGSize = .zero) -> Self {
        guard !gradientType.colors.isEmpty else { return self }
        if gradientType.colors.count == 1 {
            // 只配置了一个色值时
            return gradientColors(gradientType, fromAlpha: 0, toAlpha: 1.0, size: size)
        }
        base.layer.sublayers?.forEach({ layer in
            if layer.name == "GRADIENTCOLORS" {
                layer.removeFromSuperlayer()
            }
        })
        let gradientLayer = CAGradientLayer()
        gradientLayer.name = "GRADIENTCOLORS"
        gradientLayer.colors = gradientType.colors.map({ $0.cgColor })
        base.layoutIfNeeded()
        gradientLayer.frame = size == .zero ? base.bounds : CGRect(origin: .zero, size: size)
        startAndEndPoint(gradientLayer, direction: gradientType)
        base.layer.insertSublayer(gradientLayer, at: 0)
        return self
    }
    
    // 根据方向计算起点与终点
    private func startAndEndPoint(_ gradientLayer: CAGradientLayer, direction: SmallP_GradientType){
      let str = direction.raw
      gradientLayer.startPoint = CGPoint(x: Int(str[str.index(str.startIndex, offsetBy: 0)..<str.index(str.endIndex, offsetBy: -3)]) ?? 0, y: Int(str[str.index(str.startIndex, offsetBy: 1)..<str.index(str.endIndex, offsetBy: -2)]) ?? 0)
      gradientLayer.endPoint = CGPoint(x: Int(str[str.index(str.startIndex, offsetBy: 2)..<str.index(str.endIndex, offsetBy: -1)]) ?? 0, y: Int(str[str.index(str.endIndex, offsetBy: -1)..<str.index(str.endIndex, offsetBy: 0)]) ?? 0)
    }
    
}

//TODO: - UILabel
extension FJMakeViewWrapper where Base: UILabel {
    
    @discardableResult
    func line(_ count: Int) -> Self {
        base.numberOfLines = count
        return self
    }
    
    @discardableResult
    func text(_ text: String) -> Self {
        base.text = text
        return self
    }
    
    @discardableResult
    func color(_ color: UIColor) -> Self {
        base.textColor = color
        return self
    }
    
    @discardableResult
    func color(_ color: String) -> Self {
        base.textColor = color.toColor
        return self
    }
    
    @discardableResult
    func font(_ font: UIFont?) -> Self {
        base.font = font
        return self
    }
    
    @discardableResult
    func mode(_ mode: NSLineBreakMode) -> Self {
        base.lineBreakMode = mode
        return self
    }
    
    @discardableResult
    func alignment(_ alignment: NSTextAlignment) -> Self {
        base.textAlignment = alignment
        return self
    }
    
    @discardableResult
    func adjustFitWidth(_ fitWidth: Bool) -> Self {
        base.adjustsFontSizeToFitWidth = fitWidth
        return self
    }
    
}

//TODO: - UIButton
extension FJMakeViewWrapper where Base: UIButton {
    
    @discardableResult
    func line(_ count: Int) -> Self {
        base.titleLabel?.numberOfLines = count
        return self
    }
    
    @discardableResult
    func text(_ text: String?, state: UIControl.State = .normal) -> Self {
        base.setTitle(text, for: state)
        return self
    }
    
    @discardableResult
    func image(_ image: UIImage?, state: UIControl.State = .normal) -> Self {
        base.setImage(image, for: state)
        return self
    }
    
    @discardableResult
    func image(_ imageName: String?, state: UIControl.State = .normal) -> Self {
        image(imageName?.toImage, state: state)
    }
    
    @discardableResult
    func bgImage(_ image: UIImage?, state: UIControl.State = .normal) -> Self {
        base.setBackgroundImage(image, for: state)
        return self
    }
    
    @discardableResult
    func bgImage(_ imageName: String?, state: UIControl.State = .normal) -> Self {
        bgImage(imageName?.toImage, state: state)
    }
    
    @discardableResult
    func color(_ color: UIColor, state: UIControl.State = .normal) -> Self {
        base.setTitleColor(color, for: state)
        return self
    }
    
    @discardableResult
    func color(_ colorHex: String, state: UIControl.State = .normal) -> Self {
        color(colorHex.toColor, state: state)
    }
    
    @discardableResult
    func font(_ font: UIFont?) -> Self {
        base.titleLabel?.font = font
        return self
    }
    
    @discardableResult
    func mode(_ mode: NSLineBreakMode) -> Self {
        base.titleLabel?.lineBreakMode = mode
        return self
    }
    
    @discardableResult
    func alignment(_ alignment: UIControl.ContentHorizontalAlignment) -> Self {
        base.contentHorizontalAlignment = alignment
        return self
    }
    
    @discardableResult
    func addTarget(_ target: Any?, selector: Selector) -> Self {
        base.addTarget(target, action: selector, for: .touchUpInside)
        return self
    }
    
}

//TODO: - UITextField
extension FJMakeViewWrapper where Base: UITextField {
    
    @discardableResult
    func text(_ text: String) -> Self {
        base.text = text
        return self
    }
    
    @discardableResult
    func color(_ color: UIColor) -> Self {
        base.textColor = color
        return self
    }
    
    @discardableResult
    func color(_ colorHex: String) -> Self {
        color(colorHex.toColor)
    }
    
    @discardableResult
    func placeholder(_ text: String) -> Self {
        base.placeholder = text
        return self
    }
    
    @discardableResult
    func font(_ font: UIFont?) -> Self {
        base.font = font
        return self
    }
    
    @discardableResult
    func alignment(_ alignment: NSTextAlignment) -> Self {
        base.textAlignment = alignment
        return self
    }
    
    @discardableResult
    func leading(_ space: CGFloat, icon: UIImage? = nil, iconSize: CGSize = .zero) -> Self {
        base.addPadding(left: space, icon: icon, iconSize: iconSize)
        return self
    }
    
    @discardableResult
    func leading(_ space: CGFloat, icon: String? = nil, iconSize: CGSize = .zero) -> Self {
        leading(space, icon: icon?.toImage, iconSize: iconSize)
    }
    
    @discardableResult
    func trailing(_ space: CGFloat, icon: UIImage? = nil, iconSize: CGSize = .zero) -> Self {
        base.addPadding(right: space, icon: icon, iconSize: iconSize)
        return self
    }
    
    @discardableResult
    func trailing(_ space: CGFloat, icon: String? = nil, iconSize: CGSize = .zero) -> Self {
        trailing(space, icon: icon?.toImage, iconSize: iconSize)
    }
    
    @discardableResult
    func editChanged(_ target: Any?, selector: Selector) -> Self {
        base.addTarget(target, action: selector, for: .editingChanged)
        return self
    }
    
}

//TODO: - UIImageView
extension FJMakeViewWrapper where Base: UIImageView {
    
    @discardableResult
    func mode(_ mode: UIImageView.ContentMode) -> Self {
        base.contentMode = mode
        return self
    }
    
    @discardableResult
    func image(_ named: String) -> Self {
        base.image = UIImage(named: named)
        return self
    }
    
    @discardableResult
    func image(_ image: UIImage?) -> Self {
        base.image = image
        return self
    }
    
    @discardableResult
    func highImage(_ named: String) -> Self {
        base.highlightedImage = UIImage(named: named)
        return self
    }
    
    @discardableResult
    func highImage(_ image: UIImage?) -> Self {
        base.highlightedImage = image
        return self
    }
}

//TODO: - UITextView
extension FJMakeViewWrapper where Base: UITextView {
    
    @discardableResult
    func text(_ text: String) -> Self {
        base.text = text
        return self
    }
    
    @discardableResult
    func color(_ color: UIColor) -> Self {
        base.textColor = color
        return self
    }
    
    @discardableResult
    func color(_ colorHex: String) -> Self {
        color(colorHex.toColor)
    }
    
    @discardableResult
    func font(_ font: UIFont?) -> Self {
        base.font = font
        return self
    }
    
    @discardableResult
    func placeholder(_ text: String) -> Self {
        base.placeholder = text
        return self
    }
    
    @discardableResult
    func placeholderColor(_ color: UIColor) -> Self {
        base.placeholderColor = color
        return self
    }
    
    @discardableResult
    func placeholderColor(_ colorHex: String) -> Self {
        placeholderColor(colorHex.toColor)
    }
    
    @discardableResult
    func placeholderFont(_ font: UIFont?) -> Self {
        base.placeholderFont = font
        return self
    }
    
    @discardableResult
    func placeholderInsets(_ insets: UIEdgeInsets) -> Self {
        base.placeholderInsets = insets
        return self
    }
    
}
